/**
 * main.js
 * 2020年1月6日 农历腊月十二
 */
//const repeat = require('./repeater');
const db = require("../tools/mongodb");
const db_config = require("./mongodb.config");
const agent = require("./agent"); //从userAgent表随机抽取
const delay = require("../tools/delay");
const format = require("../tools/format");
format();
const commentsFn = require("./comments");
const waitMillis = 100;
const randomMillis = function () {
  return Math.random() * 100;
};
//const logger = require('../tools/logger');
const newComponentLimit = 100;

const summary = db_config.jd.summary;
const replies = db_config.jd.replies;
const images = db_config.jd.images;
const videos = db_config.jd.videos;
const comments = db_config.jd.comments;
const log = db_config.jd.log;
const trace = db_config.jd.trace;

const _insertNormalCommentsByResponse = async (r) => {
  try {
    let arrays = {
      body: [],
      replies: [],
      images: [],
      videos: [],
    };
    for (let c of r.comments) {
      let _comment = commentsFn.convertCommentBody(c);
      _comment.skuId = r.productCommentSummary.skuId;
      arrays.body.push(_comment);
      let _replies = commentsFn.convertCommentReplies(c);
      arrays.replies = [...arrays.replies, ..._replies];
      let _images = commentsFn.convertCommentImages(c);
      arrays.images = [...arrays.images, ..._images];
      let _videos = commentsFn.convertCommentVideos(c);
      arrays.videos = [...arrays.videos, ..._videos];
      if (c.afterUserComment && c.afterUserComment.id) {
        let after = commentsFn.convertAfterComment(c);
        _comment = { ..._comment, ...after.body };
        _images = [..._images, ...after.images];
        _videos = [..._videos, ...after.videos];
        _replies = [..._replies, ...after.replies];
      }
    }
    if (arrays.body.length > 0) {
      await db
        .insertMany(comments, arrays.body)
        .then(async (r) => {})
        .catch((error) => {
          throw { ...error, ...arrays };
        });
      if (arrays.replies.length > 0) {
        await db
          .insertMany(replies, arrays.replies)
          .then(async (r) => {})
          .catch((error) => {
            throw { ...error, ...arrays };
          });
      }
      if (arrays.images.length > 0) {
        await db
          .insertMany(images, arrays.images)
          .then(async (r) => {})
          .catch((error) => {
            throw { ...error, ...arrays };
          });
      }
      if (arrays.videos.length > 0) {
        await db
          .insertMany(videos, arrays.videos)
          .then(async (r) => {})
          .catch((error) => {
            throw { ...error, ...arrays };
          });
      }
    }
    return {
      result: "success",
      length: arrays.body.length,
    };
  } catch (error) {
    return {
      result: "error",
      error: error,
    };
  }
};

let app = async () => {
  let logError = []; //记录流程中出现的不抛出的错误
  //const commentIdTrack = db_config.jd.commentIdTrack;
  let logId = Number(new Date());
  let updateList = []; //记录有变更的skuId用于最后补充到log
  let startTime = new Date(logId).format("yyyy-MM-dd HH:mm:ss");
  try {
    let _idArray = []; //存储_id 减少内存占用————2020年3月20日
    await db
      .find(summary, { disabled: { $ne: "1" } })
      .then(async (r) => {
        _idArray = r.map((item) => {
          return item._id;
        });
      })
      .catch((error) => {
        throw error;
      });
    //console.log(`本次任务需处理${_idArray.length}个商品`);
    db.insertOne(log, {
      logId: logId,
      start: startTime,
      content: `本次任务需处理${_idArray.length}个商品`,
      operation: "crawl",
    });
    for (let _id of _idArray) {
      let smy = {};
      await db
        .find(summary, { _id: _id })
        .then((r) => {
          smy = r[0];
        })
        .catch((error) => {
          throw error;
        });
      // await db.deleteMany(trace, {});
      /*
                    ※※※※※※※update/changeTime 字段※※※※※※※
                    smy update字段指只要完成循环即更新
                    smy change字段需要判断评论数（score1~5）是否有改变
                */
      let update = true;
      let change = false;
      delete smy._id; //删除对象内的重复id，避免写入时报错
      // await db.updateMany(
      //   summary,
      //   { skuId: smy.skuId },
      //   { skuId: smy.skuId.toString() }
      // ); //设置skuId 为字符串
      smy.skuId = smy.skuId.toString();
      let logTrack = []; //记录操作流程;
      try {
        //console.clear();//不保留太多console
        //console.log(`${new Date().format('yyyy-MM-dd HH:mm:ss')}:${smy.skuId}`);
        //获取并更新summary
        try {
          await agent
            .getSummary(smy.skuId)
            .then(async (r) => {
              await db.updateMany(summary, { skuId: smy.skuId.toString() }, r);
            })
            .catch((error) => {
              throw error;
            });
        } catch (error) {
          //console.error(error);
          logError.push({
            skuId: smy.skuId,
            error: error,
            context: "获取/更新summary",
            stack: error.stack
          });
          let A = 1;
          continue;
        }
        let smy_new = {};
        //获取更新后的summary数据
        await db
          .find(summary, { skuId: smy.skuId })
          .then((r) => {
            smy_new = r[0];
            smy_new.skuId = smy.skuId.toString();
            delete smy._id; //避免重复id
          })
          .catch((error) => {
            throw error;
          });
        await delay(randomMillis());
        //获取首页数据(各类评论数量)
        let firstPage = {};
        try {
          await agent
            .getComments(smy_new, 0)
            .then(async (r) => {
              firstPage = commentsFn.firstPage(r);
            })
            .catch((error) => {
              throw error;
            });
        } catch (error) {
          console.error(error); //写入日志
          logError.push({
            skuId: smy.skuId,
            error: error,
            context: "获取首页数据",
            stack: error.stack,
          });
          continue; //切换下一个品番
        }
        //以首页获取到的评论数量作为判断条件,获取各评分评论
        let compare = commentsFn.scoreCompare(smy_new, firstPage); //转换为Map类型，按jd评论分组进行判断(5,43,21)
        for (let pair of compare) {
          let score = pair[0]; //ajax参数
          let increment = pair[1]; //差值
          if (increment == 0) continue;
          //summary评论数commentCount为0的品号，只取前newComponentLimit条记录
          if (Number(smy_new.commentCount) == 0) {
            increment =
              increment < newComponentLimit ? increment : newComponentLimit;
          }
          let gain = 0,
            page = 0;
          let emptyPage = false;
          while (gain < increment) {
            try {
              await agent
                .getComments(smy_new, page, score)
                .then(async (r) => {
                  if (r.comments.length == 0) {
                    emptyPage = true;
                    throw `score${score}page${page}为空!`;
                  }
                  page++;
                  let _operResult = {};
                  await _insertNormalCommentsByResponse(r)
                    .then((r) => {
                      _operResult = r;
                    })
                    .catch((error) => {
                      throw error;
                    }); //复用方法
                  if (_operResult.result == "error") {
                    throw _operResult.error;
                  }
                  gain += _operResult.length; //数量足够时
                })
                .catch((error) => {
                  throw error;
                });
            } catch (error) {
              //db记录错误
              if (emptyPage) {
                break;
              } else {
                logError.push({
                  skuId:smy.skuId,
                  error: error,
                  context: "根据评论数变化，按页获取数据",
                  stack: error.stack,
                });
                console.error(error);
              }
              continue; //跳出到下一页
            }
            await delay(randomMillis()); //分页延时
          }
          //避免漏评论，额外补充页数 2020年4月16日
        /*   if (score != 3) {
            //跳过好评
            if (!emptyPage) {
              let extraPages =
                smy.extraPages && !Number.isNaN(smy.extraPages)
                  ? smy.extraPages
                  : 1; //默认多跑一页
              page++;
              for (let i = 0; i < extraPages; i++) {
                try {
                  await agent
                    .getComments(smy_new, page, score)
                    .then(async (r) => {
                      if (r.comments.length == 0) {
                        emptyPage = true;
                        throw `score${score}page${page}为空!`;
                      }
                      page++;
                      let _operResult = {};
                      await _insertNormalCommentsByResponse(r)
                        .then((r) => {
                          _operResult = r;
                        })
                        .catch((error) => {
                          throw error;
                        }); //复用方法
                    })
                    .catch((error) => {
                      throw error;
                    });
                } catch (error) {
                  //db记录错误
                  if (emptyPage) {
                    break;
                  } else {
                    logError.push({
                      skuId: smy.skuId,
                      error: error,
                      context: "获取补充页码数据",
                      stack: error.stack,
                    });
                    console.error(error);
                  }
                  continue; //跳出到下一页
                }
              }
            }
          } */
          change = true;
        }
        /**更新afterCount:追评 score = 5
         * 更新replies:客服回应 score 无
         * 更新images:晒图 score = 4
         * 更新videos:视频晒单 score = 7
         */
        let compare_A = firstPage.afterCount - smy_new.afterCount;
        if (compare_A > 0) {
          //summary评论数commentCount为0的品号，只取前newComponentLimit条记录
          if (Number(smy_new.commentCount) == 0) {
            compare_A =
              compare_A < newComponentLimit ? compare_A : newComponentLimit;
          }
          logTrack.push({ time: new Date(), memo: `开始更新追评信息` });
          let gain = 0;
          let page = 0;
          let emptyPage = false;
          while (gain < compare_A) {
            try {
              await agent
                .getComments(smy_new, page, 5)
                .then(async (r) => {
                  if (r.comments.length == 0) {
                    emptyPage = true;
                    throw `score${score}page${page}为空!`;
                  }
                  page++;
                  let _operResult = {};
                  await _insertNormalCommentsByResponse(r)
                    .then((r) => {
                      _operResult = r;
                    })
                    .catch((error) => {
                      throw error;
                    }); //复用方法
                  if (_operResult.result == "error") {
                    throw _operResult.error;
                  }
                  gain += _operResult.length; //数量足够时
                })
                .catch((error) => {
                  throw error;
                });
            } catch (error) {
              if (emptyPage) {
                break;
              } else {
                logError.push({
                  skuId: smy.skuId,
                  error: error,
                  context: "获取补充页码数据(追评)",
                  stack: error.stack,
                });
                console.error(error);
              }
              continue;
            }
            await delay(randomMillis()); //分页延时
          }
          //避免漏评论，额外补充页数 2020年4月16日
         /*  if (!emptyPage) {
            let extraPages =
              smy.extraPages && !Number.isNaN(smy.extraPages)
                ? smy.extraPages
                : 1; //默认多跑一页
            for (let i = 0; i < extraPages; i++) {
              try {
                await agent
                  .getComments(smy_new, page, 5)
                  .then(async (r) => {
                    if (r.comments.length == 0) {
                      emptyPage = true;
                      throw `score${score}page${page}为空!`;
                    }
                    page++;
                    let _operResult = {};
                    await _insertNormalCommentsByResponse(r)
                      .then((r) => {
                        _operResult = r;
                      })
                      .catch((error) => {
                        throw error;
                      }); //复用方法
                    if (_operResult.result == "error") {
                      throw _operResult.error;
                    }
                    gain += _operResult.length; //数量足够时
                  })
                  .catch((error) => {
                    throw error;
                  });
              } catch (error) {
                //db记录错误
                if (emptyPage) {
                  break;
                } else {
                  logError.push({
                    skuId: smy.skuId,
                    error: error,
                    context: "获取补充页码数据(追评)",
                    stack: error.stack,
                  });
                  console.error(error);
                }
                continue; //跳出到下一页
              }
            }
          } */
          update = true;
        }
        /**
         * 图片/视频/处理方案：直接只翻查n页,获取完整评论，交由社内数据库进行清洗
         */
      /*   let extraPages =
          smy.extraPages && !Number.isNaN(smy.extraPages) ? smy.extraPages : 1; //默认多跑一页
        let scoredict = {
          images: 4,
          videos: 7,
        };
        for (let key of scoredict) {
          let page = 0;
          let emptyPage = false;
          for (let i = 0; i < extraPages; i++) {
            try {
              await agent
                .getComments(smy_new, page, scoredict[key])
                .then(async (r) => {
                  if (r.comments.length == 0) {
                    emptyPage = true;
                    throw `score${score}page${page}为空!`;
                  }
                  page++;
                  let _operResult = {};
                  await _insertNormalCommentsByResponse(r)
                    .then((r) => {
                      _operResult = r;
                    })
                    .catch((error) => {
                      throw error;
                    }); //复用方法
                  if (_operResult.result == "error") {
                    throw _operResult.error;
                  }
                })
                .catch((error) => {
                  throw error;
                });
            } catch (error) {
              if (emptyPage) {
                break;
              } else {
                logError.push({
                  skuId: smy.skuId,
                  error: error,
                  context: "获取补充页码数据(追评)",
                  stack: error.stack,
                });
                console.error(error);
              }
              continue; //跳出到下一页
            }
          }
        } */
        updateList.push(smy.skuId.toString());
        await delay(randomMillis()); //延时减轻写入负载
        let summary_update = {
          ...firstPage,
          ...{ update: new Date().format("yyyy-MM-dd HH:mm:ss") },
        };
        if (change == true) {
          summary_update = {
            ...summary_update,
            ...{ changeTime: new Date().format("yyyy-MM-dd HH:mm:ss") },
          };
        }
        await db.updateMany(summary, { skuId: smy.skuId }, summary_update);
        //logTrack.push({ time: new Date(), memo: `更新summary!` });
        // updateList.push(smy.skuId.toString());
      } catch (error) {
        // console.error(error);
        continue;
      }
      //}//for(let smy of r)
    }
    await db.updateMany(
      log,
      { logId: logId },
      {
        end: new Date().format("yyyy-MM-dd HH:mm:ss"),
        content: `本次任务共变更${updateList.length}个商品`,
        error: logError,
        updateList: updateList,
      }
    );
  } catch (error) {
    await db.insertOne(db_config.jd.error, {
      logId: logId,
      error: error,
      stack: error.stack,
      time: new Date(),
    });
    console.error(error);
  }
};
module.exports = app;
